#ifndef CELL_BASE_HPP
#define CELL_BASE_HPP

#include "meshTypes_fwd.hpp"
#include "crtpBase.hpp"
#include <type_traits>

namespace hms
{

template<typename CellType>
class CellTraits{};

/**
 * @brief Common interface for cell types.
 * 
 * @tparam CellType 
 * 
 * Cells are thin wrapper classes providing access to cell functions such as
 * area(), centroid() etc.
 * 
 * @see EdgeBase, MeshBase, Cell, StructCellBase
 */
template<typename CellType>
class CellBase : public CrtpBase<CellType>
{
public:
	using Traits = CellTraits<CellType>;
	using MeshType     = typename Traits::MeshType;
	using CentroidType = typename Traits::CentroidType;
	using EdgeIndices  = typename Traits::EdgeIndices;
public:
	/**
	 * @brief Returns the parent mesh to which the cell belongs.
	 * 
	 * @return const MeshType&, which has the type specified by
	 * CellTraits<CellType>::MeshType (e.g. StructMesh for StructCell).
	 */
	auto mesh() const -> const MeshType&;
	
	/**
	 * @brief Returns the index of the cell within the parent mesh.
	 * 
	 * @return Index 
	 */
	auto index() const -> Index;

	/**
	 * @brief Returns the area of the cell. For ghost cells,
	 * it returns the neighbouring domain cell's value.
	 * 
	 * @return scalar 
	 */
	auto area() const -> scalar;

	/**
	 * @brief Returns the circumference of the cell. For ghost cells,
	 * it returns the neighbouring domain cell's value.
	 * 
	 * @return scalar 
	 */
	auto circumf() const -> scalar;

	/**
	 * @brief Returns the cell's centroid (~=midpoint).
	 * 
	 * @return CentroidType
	 * 
	 * All cell types must provide a calculation that provides the same result
	 * as if verticesToCentroid() was called.
	 */
	auto centroid() const -> CentroidType;

	/**
	 * @brief Returns the indices of the edges forming the cell.
	 * 
	 * @return EdgeIndices 
	 * 
	 * Use with domain cells. Triggers assertion if used on ghost cells.
	 */
	auto edges() const -> EdgeIndices;

	/**
	 * @brief Returns the index of the boundary edge which the ghost cell
	 * belongs to.
	 * 
	 * @return Index 
	 * 
	 * Use with ghost cells. Triggers assertion if used on domain cells.
	 */
	auto edge() const -> Index;

	/**
	 * @brief Returns the number of edges of a cell. Can be 1 (ghost cells)
	 * 3 or 4.
	 * 
	 * @return char 
	 */
	auto nEdges() const -> char;

	/**
	 * @brief Returns true if the cell is a ghost cell and false otherwise.
	 * 
	 */
	auto isGhost() const -> bool;

	auto domainCell() const -> CellType;

	/**
	 * @brief Returns true if the cell is a domain cell with at least one
	 * boundary edge and false otherwise.
	 * 
	 */
	auto isBoundary() const -> bool;

	/**
	 * @brief Returns the indices of all directly adjacent cells.
	 * 
	 * @return IdxVector 
	 */
	auto neighbours() const -> ArrayXi;

	/**
	 * @brief Returns the indices of the cell's vertices (~=corners).
	 * Using such an index as the argument to MeshBase<MeshType>::vertex()
	 * yields the vertex' coordinates.
	 * 
	 * @param ordered 
	 * @return IdxVector 
	 */
	auto vertices  (bool ordered = false) const -> ArrayXi;

protected:
	CellBase();
};

} // end namespace hms

#endif